API en Python
  • Back to Main Website
  • Home
  • Introduction aux API
    • Introduction aux API
    • API - Définition
    • Utiliser une API
    • Créer une API
    • Sécuriser une API
    • Concepts élargis

    • Travaux Pratiques
    • TP - Premiere requêtes
  • Consommation avancée d’API
    • Consommation avancée d’API
    • Protocols de communication
    • Authentification et sécurité des API
    • Optimisation des ressources et de la performance des API

    • Travaux Pratiques
    • TP : Comparaison des performances des appels en tant qu’utilisateur
  • Communication entre Processus (IPC)
    • Communication entre Processus (IPC)
    • Introduction à l’IPC
    • Sockets
    • Fichiers et IPC
    • Shared Memory
    • Pipes
    • gRPC
    • Conclusions

    • Travaux Pratiques
    • TP3 Option 1 Service gRPC pour indicateurs de marché
    • TP3 Option 2 Serveur de Données de Marché via Socket et Mémoire Partagée
  • Conception d’APIs
    • Conception d’APIs
    • Introduction à la Conception d’APIs
    • Les principaux Frameworks d’APIs en Python
    • Fast API
    • Django REST Framework
    • Tester et documenter une API
    • Bonne pratique générale
    • Conclusion

    • Travaux Pratiques
    • TP 4 : API d’Indicateurs Financiers avec Gestion des Niveaux d’Accès
  • Déploiement d’API - Principes Généraux et Mise en Pratique avec Heroku
    • Déploiement d’API - Principes Généraux et Mise en Pratique avec Heroku
    • Introduction au Déploiement d’API
    • Heroku - Présentation du service
    • Meilleurs Pratiques avant un déploiement
    • Deploiement sur Heroku
    • Déploiement avancé
    • Bonus - Nom de Domaine
    • Conclusion
  • Sujets de Projets possibles
    • Projets
    • M2EIF Quant 2023/2024
    • M2EIF Quant 2024/2025
  • Code source
  1. Bonne pratique générale
  • Conception d’APIs
  • Introduction à la Conception d’APIs
  • Les principaux Frameworks d’APIs en Python
  • content/Cours_4//3-Falsk.qmd
  • Fast API
  • Django REST Framework
  • Tester et documenter une API
  • Bonne pratique générale
  • Conclusion
  • Travaux Pratiques
    • TP 4 : API d’Indicateurs Financiers avec Gestion des Niveaux d’Accès

On this page

  • Asynchronie et Multiprocessing - comment donner le tournis au GIL
  • VII. Bonnes Pratiques de Conception d’APIs
    • 1. Conception RESTful
    • 2. Gestion des erreurs
    • 3. Pagination, Filtrage et Tri des données
      • a. Exemple de pagination dans Django Rest Framework
      • b. Exemple de filtrage et de tri pour une API utilisant Django Rest Framework
    • 4. Rate Limiting et Caching

Bonne pratique générale

Cours
Fondamentaux
Author

Remi Genet

Published

2024-12-10

Asynchronie et Multiprocessing - comment donner le tournis au GIL


VII. Bonnes Pratiques de Conception d’APIs

La conception d’une API est un élément fondamental qui détermine sa facilité d’utilisation, sa performance et sa maintenabilité. Voici quelques bonnes pratiques à considérer lors de la conception d’une API.

1. Conception RESTful

RESTful fait référence à une API qui suit les contraintes de l’architecture REST (Representational State Transfer). Cela signifie que l’API utilise des méthodes HTTP standard sans maintenir l’état du client entre les requêtes, ce qui la rend sans état. Les données sont représentées de manière standard (comme JSON ou XML), et les opérations sur les données sont effectuées à l’aide de méthodes HTTP (comme GET, POST, PUT, DELETE).

Un exemple d’API RESTful est une API qui gère les utilisateurs. Les URIs sont structurées de manière logique, par exemple :

  • GET /users pour récupérer une liste d’utilisateurs.
  • POST /users pour créer un nouvel utilisateur.
  1. Utilisation correcte des méthodes HTTP : GET pour récupérer des données, POST pour créer des données, PUT/PATCH pour mettre à jour et DELETE pour supprimer.
  2. Des URIs bien structurées : Les URIs doivent être intuitives et hiérarchiques, reflétant les relations entre les ressources.
  3. Sans état : Chaque requête doit contenir toutes les informations nécessaires pour être traitée, sans dépendre d’un état stocké sur le serveur.
  4. Cacheable : Les réponses doivent être définies comme cacheables ou non, pour améliorer les performances.
  5. Système de couche : L’API doit être structurée en couches, chaque couche ayant une fonction spécifique.

2. Gestion des erreurs

Une bonne gestion des erreurs est essentielle pour aider les développeurs à comprendre ce qui ne va pas lorsqu’une requête échoue. Voici quelques recommandations :

  1. Utiliser des codes d’état HTTP appropriés : Par exemple, 404 pour “Non trouvé”, 400 pour “Mauvaise requête”, 500 pour “Erreur interne du serveur”.
  2. Fournir des messages d’erreur descriptifs : Inclure des messages d’erreur clairs et, si possible, des indications sur la façon de résoudre le problème.
  3. Standardiser les réponses d’erreur : Utiliser un format cohérent pour toutes les réponses d’erreur.

Voici un exemple de gestion des erreurs dans Flask :

from flask import Flask, jsonify, make_response

app = Flask(__name__)

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

@app.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    user = find_user_by_id(user_id)
    if user is None:
        return not_found('Not found')
    return jsonify({'user': user})

Dans cet exemple, @app.errorhandler(404) est un décorateur qui définit une fonction personnalisée pour gérer les erreurs 404, renvoyant un message JSON et le code d’état approprié.

3. Pagination, Filtrage et Tri des données

Lorsque vous travaillez avec de grandes collections de données, il est important de fournir des mécanismes pour la pagination, le filtrage et le tri :

  1. Pagination : Limiter le nombre d’éléments renvoyés dans une seule réponse et fournir des liens pour accéder aux pages suivantes.
  2. Filtrage : Permettre aux utilisateurs de spécifier des critères pour limiter les données renvoyées.
  3. Tri : Offrir la possibilité de trier les données selon différents attributs.

a. Exemple de pagination dans Django Rest Framework

from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import User
from .serializers import UserSerializer

class UserListView(APIView):
    pagination_class = PageNumberPagination

    def get(self, request, format=None):
        users = User.objects.all()
        paginator = self.pagination_class()
        page = paginator.paginate_queryset(users, request)
        
        if page is not None:
            serializer = UserSerializer(page, many=True)
            return paginator.get_paginated_response(serializer.data)
        
        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)

Ce code montre comment implémenter la pagination dans une vue qui renvoie une liste d’utilisateurs. Le PageNumberPagination est utilisé pour diviser les résultats en pages.

b. Exemple de filtrage et de tri pour une API utilisant Django Rest Framework

Nous allons utiliser le modèle User et le serializer UserSerializer pour illustrer comment filtrer et trier les données renvoyées par une requête GET.

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics
from .models import User
from .serializers import UserSerializer

class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['username', 'email']  # Fields to filter by
    ordering_fields = ['username', 'date_joined']  # Fields to order by

    def get_queryset(self):
        """
        Optionally restricts the returned users to a given user,
        by filtering against a username query parameter in the URL.
        """
        queryset = User.objects.all()
        username = self.request.query_params.get('username')
        if username is not None:
            queryset = queryset.filter(username=username)
        return queryset

Dans cet exemple, DjangoFilterBackend est utilisé pour ajouter des capacités de filtrage à la vue. Les utilisateurs peuvent filtrer les résultats en ajoutant des paramètres de requête à l’URL, comme ?username=johndoe pour filtrer par nom d’utilisateur, ou ?email=johndoe@example.com pour filtrer par e-mail.

Le tri est géré par ordering_fields, qui spécifie les champs sur lesquels les utilisateurs peuvent trier les résultats. Les utilisateurs peuvent ajouter un paramètre de requête ordering à l’URL, comme ?ordering=username pour trier par nom d’utilisateur ou ?ordering=-date_joined pour trier par date d’inscription en ordre décroissant (le signe moins indique un tri décroissant).

Ces fonctionnalités permettent aux utilisateurs de l’API de récupérer des données de manière plus précise et organisée, améliorant ainsi l’expérience utilisateur et la performance de l’API.

4. Rate Limiting et Caching

Pour protéger votre API contre les abus et gérer les ressources serveur de manière efficace :

  1. Rate Limiting : Imposer des limites sur le nombre de requêtes qu’un utilisateur peut faire dans un certain intervalle de temps.
  2. Caching : Utiliser des caches pour stocker les réponses des requêtes fréquemment faites afin de réduire la charge sur le serveur et d’améliorer les temps de réponse.

Pour le rate limiting dans FastAPI, vous pourriez utiliser un middleware personnalisé :

from fastapi import FastAPI, Request, HTTPException
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

limiter = Limiter(key_func=get_remote_address)
app = FastAPI()

app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.middleware("http")
async def rate_limit_middleware(request: Request, call_next):
    response = await call_next(request)
    return response

@app.get("/users")
@limiter.limit("5/minute")
async def get_users():
    return [{"user": "user1"}, {"user": "user2"}]

Dans cet exemple, le décorateur @limiter.limit(“5/minute”) est utilisé pour limiter les requêtes à 5 par minute pour l’endpoint /users.

Pour le caching, vous pourriez utiliser Flask-Caching dans une application Flask :

from flask import Flask
from flask_caching import Cache

app = Flask(__name__)
cache = Cache(app, config={'CACHE_TYPE': 'simple'})

@app.route('/')
@cache.cached(timeout=50)
def index():
    return "Ceci est une page mise en cache"

Ici, @cache.cached(timeout=50) est utilisé pour mettre en cache la réponse de l’endpoint racine pendant 50 secondes.

Ces bonnes pratiques sont essentielles pour créer une API robuste, performante et sécurisée. Elles contribuent également à une meilleure expérience pour les développeurs qui utilisent votre API, en leur fournissant des mécanismes clairs et des directives pour intégrer l’API dans leurs applications.

Back to top
Tester et documenter une API
Conclusion

Python API, Rémi Genet.
Licence
Code source disponible sur Github

 

Site construit avec et Quarto
Inspiration pour la mise en forme du site ici
Code source disponible sur GitHub